package com.gonsin.license.processors;

import com.gonsin.license.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.quartz.JobDataMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.gonsin.license.GLicenseAutoSelector.DEVICE;

/**
 * 本地授权逻辑，如果本地授权文件存在，则运行该流程
 */
@Slf4j
@Component
public class LicenseLocalProcessor {

    @Autowired
    private LicenseExtraService extraService;

    /**
     * 本地授权检测
     */
    public boolean validateLicense(String uuid, File licenseFile) throws Exception {
        // 检测授权
        Map<String,Object> data = getLicenseFileInfo(uuid,licenseFile);
        // 检测设备
        if (!uuid.equals(data.get("uuid"))) {
            log.warn("License file is not for this device!");
            return false;
        }

        // 检测设备类型
        if (!DEVICE.equals(data.get("type"))) {
            log.warn("License file wrong, type error!");
            return false;
        }

        // 检测时间
        String validate = (String) data.get("validate");
        if(!validate.equals("forever")){
            boolean createJobResult = createDelayExpireJob(validate);
            if(!createJobResult){
                return false;
            }
        }
        log.info("授权成功");
        extraService.setExtra(data.get("extra") == null ? null : data.get("extra").toString());
        extraService.setVersion(data.get("version") == null ? null : data.get("version").toString());
        return true;
    }

    /**
     * 获取授权文件信息
     * @param uuid id
     * @param licenseFile 授权文件
     * @return Map<String,Object>
     */
    public Map<String,Object> getLicenseFileInfo(String uuid, File licenseFile) throws Exception{
        String secret = FileUtils.readFileToString(licenseFile, "UTF8");

        // 解码逻辑
        // 1、读取授权文件原文，并进行AES解码，秘钥为 gonsin ，偏移量 为 gonsin
        // 2、解码后的内容，格式为 <不定长度 AES密文><1位 字符A><32位 UUID>    末尾32个字符，为本设备的uuid(大写)
        // 3、去除末尾的32个字符，再去除末尾的“A”， 之后剩余的内容，再进行一次AES解码，秘钥为gonsin，偏移量为 gonsin
        // 4、以上2次解码后的内容，是一个json字符串，里面包含的就是授权所有的信息，其结构如下
        /*
         {
            "device": "",           // 设备的32位 uuid
            "type": "",             // 设备的device类型，例如venus
            "validate": ""          // 设备的授权时间，如果是 "forever" ，表示 永久，如果取值为 具体时间（例如 "2024/7/25"），就表示该天的24点之后就授权失效
            "extra":""              // 20240715新增extra字段，用于客户端自行定义额外功能，客户端可以填充例如授权功能列表，各个权限开通的时间等。
            "version": ""           // 20240715新增version字段，用于标记该json文件的格式，初始版本为“v1-20240715”表示从20240715开始标记的v1版本，
                                    // 后续该json格式有更改的话，应该为“v2-更改的日期”
         }
         */
        // 5、一旦授权检测到授权是有效的，需要修改 licensed为true，让过滤器可以通过所有请求。


        String json = AESUtil.decryptAES(secret, "gonsin", "gonsin");
        if(json == null){
            return new HashMap<>();
        }
        int index = json.lastIndexOf(uuid);
        if(index < 0){
            return new HashMap<>();
        }
        json = json.substring(0, index - 1);
        json = AESUtil.decryptAES(json, "gonsin", "gonsin");

        Map<String, Object> data = JsonUtils.fromJson(json);
        return data;
    }

    public boolean createDelayExpireJob(String validate){
        String[] dateStr = validate.split("/");
        int year = Integer.parseInt(dateStr[0]);
        int month = Integer.parseInt(dateStr[1]);
        int day = Integer.parseInt(dateStr[2]);

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.DATE, day + 1);
        calendar.set(Calendar.HOUR, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date validateDate = calendar.getTime();

        long now = System.currentTimeMillis();
        if(now > validateDate.getTime()){
            log.warn("License file has past validity already, please contact us for support!");
            return false;
        }
        QuartzUtil.removeJob("CHECK_LICENSE",
                "CHECK_LICENSE",
                "CHECK_LICENSE",
                "CHECK_LICENSE");
        QuartzUtil.addDelayJob(
                "CHECK_LICENSE",
                "CHECK_LICENSE",
                "CHECK_LICENSE",
                "CHECK_LICENSE",
                CheckLicenseTask.class,
                validateDate.getTime(),
                new JobDataMap());
        return true;
    }
}
